package cn.com.bsoft.cloud.utils.test;

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;


/**
 * @author Administrator
 *
 */
public class RSAJavaToCSharp {
    private static final String KEY_ALGORITHM = "RSA";

//        String YY_PRIVATE_KEY="MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALBj+0bUczodxxEdOOrHDHZFOkU3DUsoSzq1uBn3yvPTP9AftbbDCsFL9n5lPAsvnoHyuL5YwcroLij+BOb94lQwgNMtahuXfzfHXNkgdkpdtabJvFIpF3k2s5+ldiclr3f+cth3xBuHCbBOFzfDFKupbOehaBPHZIMNneFxPcxVAgMBAAECgYEAi9k5SBb4pIMnaTI6Bip6fuq0IFxdddEklA+vPydvCZHbbi816wkIZejMLboluNiwW2cNghzsyOr8bhO330w7PB8aQ3cRL1aC2YP/81u6qZcdVrCMN4rBEuc9rNIjqGwX4D1l3oI0zboc/qliEKKZ890fWhnc4UJxCHCq07D8J6ECQQD6VkvfoMJfpSO/rLaZWoHsTeo+FBkb1xfUo/W4UX5Vc/OuOfe7Hr9Bj5LA3ax9YnPGeVbELEiYmM3K3jsP6vaDAkEAtGF11iOn7mk7r+dbvXiyeujUy89wtfHCV50GbyGcoqrXupKvba53Mncx5dNzDGncLCslDvDZuvGmgtxSkLN6RwJBAJhNaFvlslv+XIGA0pb6OZFK1fhuwdfuRNFZ72T0L6hNozOckNuHGVUJxH8SXp7qBwX5TJCNYJ12Wb3S9pv4l4ECQEGvT9K3zzoxFewbSrv3TL8XNA43ruqCa+utoZ8sVTajEcW+DqXZJ0y4PPJdCoMVtXhcCbWkHRVHVARJKMPKp5cCQQCV0wZ48jcHAI85pQkOxeUgnwh7PMuk2KkQ/RnhWIMZWqHeKBDJVO/Z6Mh7cpzjGrwlvFk1Bndbn4FbXxaquuEp";
//
//        String YY_PUBLIC_KEY="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwY/tG1HM6HccRHTjqxwx2RTpFNw1LKEs6tbgZ98rz0z/QH7W2wwrBS/Z+ZTwLL56B8ri+WMHK6C4o/gTm/eJUMIDTLWobl383x1zZIHZKXbWmybxSKRd5NrOfpXYnJa93/nLYd8QbhwmwThc3wxSrqWznoWgTx2SDDZ3hcT3MVQIDAQAB";


    public static void main(String[] args) throws Exception {
        String YY_PRIVATE_KEY="MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALBj+0bUczodxxEdOOrHDHZFOkU3DUsoSzq1uBn3yvPTP9AftbbDCsFL9n5lPAsvnoHyuL5YwcroLij+BOb94lQwgNMtahuXfzfHXNkgdkpdtabJvFIpF3k2s5+ldiclr3f+cth3xBuHCbBOFzfDFKupbOehaBPHZIMNneFxPcxVAgMBAAECgYEAi9k5SBb4pIMnaTI6Bip6fuq0IFxdddEklA+vPydvCZHbbi816wkIZejMLboluNiwW2cNghzsyOr8bhO330w7PB8aQ3cRL1aC2YP/81u6qZcdVrCMN4rBEuc9rNIjqGwX4D1l3oI0zboc/qliEKKZ890fWhnc4UJxCHCq07D8J6ECQQD6VkvfoMJfpSO/rLaZWoHsTeo+FBkb1xfUo/W4UX5Vc/OuOfe7Hr9Bj5LA3ax9YnPGeVbELEiYmM3K3jsP6vaDAkEAtGF11iOn7mk7r+dbvXiyeujUy89wtfHCV50GbyGcoqrXupKvba53Mncx5dNzDGncLCslDvDZuvGmgtxSkLN6RwJBAJhNaFvlslv+XIGA0pb6OZFK1fhuwdfuRNFZ72T0L6hNozOckNuHGVUJxH8SXp7qBwX5TJCNYJ12Wb3S9pv4l4ECQEGvT9K3zzoxFewbSrv3TL8XNA43ruqCa+utoZ8sVTajEcW+DqXZJ0y4PPJdCoMVtXhcCbWkHRVHVARJKMPKp5cCQQCV0wZ48jcHAI85pQkOxeUgnwh7PMuk2KkQ/RnhWIMZWqHeKBDJVO/Z6Mh7cpzjGrwlvFk1Bndbn4FbXxaquuEp";

        String YY_PUBLIC_KEY="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwY/tG1HM6HccRHTjqxwx2RTpFNw1LKEs6tbgZ98rz0z/QH7W2wwrBS/Z+ZTwLL56B8ri+WMHK6C4o/gTm/eJUMIDTLWobl383x1zZIHZKXbWmybxSKRd5NrOfpXYnJa93/nLYd8QbhwmwThc3wxSrqWznoWgTx2SDDZ3hcT3MVQIDAQAB";

        HashMap<String, Object> map = getKeys();
//        System.out.println("");
        RSAPublicKey publicKey = getPublicKey(YY_PUBLIC_KEY);
        RSAPrivateKey privateKey =getPrivateKey(YY_PRIVATE_KEY);

//        RSAPublicKey publicKey = (RSAPublicKey) map.get("PUBLIC");
//        RSAPrivateKey privateKey = (RSAPrivateKey) map.get("PRIVATE");

        String publicKeyString = getRSAPublicKeyAsNetFormat(publicKey.getEncoded());
        String privateKeyString = getRSAPrivateKeyAsNetFormat(privateKey.getEncoded());

        System.out.println(encodeBase64(publicKey.getEncoded()));//此处为客户端加密时需要的公钥字符串
        System.out.println(encodePublicKeyToXml(publicKey));
        System.out.println(publicKeyString);
        System.out.println(privateKeyString);
    }




    public static RSAPublicKey getPublicKey(String publicKey) throws Exception{
        byte[] keyBytes = Base64.decode(publicKey);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        return (RSAPublicKey) keyFactory.generatePublic(spec);
    }

    public static RSAPrivateKey getPrivateKey(String privateKey) throws Exception{
        byte[] keyBytes = Base64.decode(privateKey);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        return (RSAPrivateKey) keyFactory.generatePrivate(spec);
    }

    /**获取密钥对
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static HashMap<String, Object> getKeys()
            throws NoSuchAlgorithmException {
        HashMap<String, Object> map = new HashMap<String, Object>();
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        keyPairGen.initialize(1024);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        map.put("PUBLIC", publicKey);
        map.put("PRIVATE", privateKey);
        return map;
    }

    /**
     * 私钥转换成C#格式
     * @param encodedPrivkey
     * @return
     */
    private static String getRSAPrivateKeyAsNetFormat(byte[] encodedPrivateKey) {
        try {
            StringBuffer buff = new StringBuffer(1024);

            PKCS8EncodedKeySpec pvkKeySpec = new PKCS8EncodedKeySpec(
                    encodedPrivateKey);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPrivateCrtKey pvkKey = (RSAPrivateCrtKey) keyFactory
                    .generatePrivate(pvkKeySpec);

            buff.append("<RSAKeyValue>");
            buff.append("<Modulus>"
                    + encodeBase64(removeMSZero(pvkKey.getModulus()
                    .toByteArray())) + "</Modulus>");

            buff.append("<Exponent>"
                    + encodeBase64(removeMSZero(pvkKey.getPublicExponent()
                    .toByteArray())) + "</Exponent>");

            buff.append("<P>"
                    + encodeBase64(removeMSZero(pvkKey.getPrimeP()
                    .toByteArray())) + "</P>");

            buff.append("<Q>"
                    + encodeBase64(removeMSZero(pvkKey.getPrimeQ()
                    .toByteArray())) + "</Q>");

            buff.append("<DP>"
                    + encodeBase64(removeMSZero(pvkKey.getPrimeExponentP()
                    .toByteArray())) + "</DP>");

            buff.append("<DQ>"
                    + encodeBase64(removeMSZero(pvkKey.getPrimeExponentQ()
                    .toByteArray())) + "</DQ>");

            buff.append("<InverseQ>"
                    + encodeBase64(removeMSZero(pvkKey.getCrtCoefficient()
                    .toByteArray())) + "</InverseQ>");

            buff.append("<D>"
                    + encodeBase64(removeMSZero(pvkKey.getPrivateExponent()
                    .toByteArray())) + "</D>");
            buff.append("</RSAKeyValue>");

            return buff.toString();
        } catch (Exception e) {
            System.err.println(e);
            return null;
        }
    }

    /**
     * 公钥转成C#格式
     * @param encodedPrivkey
     * @return
     */
    private static String getRSAPublicKeyAsNetFormat(byte[] encodedPublicKey) {
        try {
            StringBuffer buff = new StringBuffer(1024);

            //Only RSAPublicKeySpec and X509EncodedKeySpec supported for RSA public keys
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPublicKey pukKey = (RSAPublicKey) keyFactory
                    .generatePublic(new X509EncodedKeySpec(encodedPublicKey));

            buff.append("<RSAKeyValue>");
            buff.append("<Modulus>"
                    + encodeBase64(removeMSZero(pukKey.getModulus()
                    .toByteArray())) + "</Modulus>");
            buff.append("<Exponent>"
                    + encodeBase64(removeMSZero(pukKey.getPublicExponent()
                    .toByteArray())) + "</Exponent>");
            buff.append("</RSAKeyValue>");
            return buff.toString();
        } catch (Exception e) {
            System.err.println(e);
            return null;
        }
    }

    /**
     * 公钥转换成C#格式
     * @param key
     * @return
     * @throws Exception
     */
    public static String encodePublicKeyToXml(PublicKey key) throws Exception {
        if (!RSAPublicKey.class.isInstance(key)) {
            return null;
        }
        RSAPublicKey pubKey = (RSAPublicKey) key;
        StringBuilder sb = new StringBuilder();

        sb.append("<RSAKeyValue>");
        sb.append("<Modulus>")
                .append(encodeBase64(removeMSZero(pubKey.getModulus()
                        .toByteArray()))).append("</Modulus>");
        sb.append("<Exponent>")
                .append(encodeBase64(removeMSZero(pubKey.getPublicExponent()
                        .toByteArray()))).append("</Exponent>");
        sb.append("</RSAKeyValue>");
        return sb.toString();
    }

    /**
     * @param data
     * @return
     */
    private static byte[] removeMSZero(byte[] data) {
        byte[] data1;
        int len = data.length;
        if (data[0] == 0) {
            data1 = new byte[data.length - 1];
            System.arraycopy(data, 1, data1, 0, len - 1);
        } else
            data1 = data;

        return data1;
    }

    /**
     * base64编码
     * @param input
     * @return
     * @throws Exception
     */
    public static String encodeBase64(byte[] input) throws Exception {
        Class clazz = Class
                .forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");
        Method mainMethod = clazz.getMethod("encode", byte[].class);
        mainMethod.setAccessible(true);
        Object retObj = mainMethod.invoke(null, new Object[] { input });
        return (String) retObj;
    }

    /**
     * base64解码
     * @param input
     * @return
     * @throws Exception
     */
    public static byte[] decodeBase64(String input) throws Exception {
        Class clazz = Class
                .forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");
        Method mainMethod = clazz.getMethod("decode", String.class);
        mainMethod.setAccessible(true);
        Object retObj = mainMethod.invoke(null, input);
        return (byte[]) retObj;
    }

    public static String byteToString(byte[] b)
            throws UnsupportedEncodingException {
        return new String(b, "utf-8");
    }
}